#include "http_server.h"
#include "elog.h"
#include "elog_file.h"
#include "file_utils.h"
#include "md5.h"
#include "http_constant.h"
#include "ws_constant.h"
#include "dwarf_utils.h"

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include <string>
#include <fstream>
#include <filesystem>
#include <sstream>
#include <mutex>
#include <iomanip>

using namespace dwarf;
namespace fs = std::filesystem;
static std::mutex upgrade_firmware_mutex;
static bool b_upgrade = false;

HttpServer::HttpServer() {
    album_ = Album();
    system_ = System();
    rgb_power_ = RgbPower();
}

HttpServer::~HttpServer() {

}

void HttpServer::setAlbumRouter() {
    // 获取相册文件总数量
    router.POST("/album/list/mediaCounts", [this](HttpRequest* req, HttpResponse* resp) {
        int picture_count = album_.album_picture_.getCount();
        int video_count = album_.album_video_.getCount();
        int burst_count = album_.album_burst_.getCount();
        int pano_count = album_.album_pano_.getCount();
        int astro_count = album_.album_astro_.getCount();

        int all_count = picture_count + video_count + burst_count + pano_count + astro_count;

        resp->json["data"] = hv::Json();

        hv::Json all_count_json;
        all_count_json["mediaType"] = MEDIA_ALL;
        all_count_json["count"] = all_count;
        resp->json["data"].push_back(all_count_json);

        hv::Json picture_count_json;
        picture_count_json["mediaType"] = MEDIA_PICTURE;
        picture_count_json["count"] = picture_count;
        resp->json["data"].push_back(picture_count_json);

        hv::Json video_count_json;
        video_count_json["mediaType"] = MEDIA_VIDEO;
        video_count_json["count"] = video_count;
        resp->json["data"].push_back(video_count_json);

        hv::Json burst_count_json;
        burst_count_json["mediaType"] = MEDIA_BURST;
        burst_count_json["count"] = burst_count;
        resp->json["data"].push_back(burst_count_json);

        hv::Json pano_count_json;
        pano_count_json["mediaType"] = MEDIA_PANO;
        pano_count_json["count"] = pano_count;
        resp->json["data"].push_back(pano_count_json);

        hv::Json astro_count_json;
        astro_count_json["mediaType"] = MEDIA_ASTRO;
        astro_count_json["count"] = astro_count;
        resp->json["data"].push_back(astro_count_json);

        resp->json["code"] = 0;

        return 200;
    });
}

hv::Json HttpServer::getAlbumPictureJson(PictureInfo& picture_info) {
    hv::Json json_object;
    json_object["mediaType"] = MEDIA_PICTURE;
    json_object["filePath"] = picture_info.common_info.file_path;
    json_object["thumbnailPath"] = picture_info.common_info.thumbnail_path;
    json_object["fileName"] = getFileName(picture_info.common_info.file_path);
    json_object["modificationTime"] = picture_info.common_info.modification_time;
    json_object["fileSize"] = picture_info.common_info.file_size;
    json_object["videoDuration"] = 0;
    json_object["burstImgCount"] = 0;
    json_object["astroTargetName"] = "";
    json_object["basicParams"] = hv::Json();
    json_object["featureParams"] = hv::Json();
    json_object["panoImgCount"] = 0;

    return json_object;
}

hv::Json HttpServer::getAlbumVideoJson(VideoInfo& video_info) {
    hv::Json json_object;
    json_object["mediaType"] = MEDIA_VIDEO;
    json_object["filePath"] = video_info.common_info.file_path;
    json_object["thumbnailPath"] = video_info.common_info.thumbnail_path;
    json_object["fileName"] = getFileName(video_info.common_info.file_path);
    json_object["modificationTime"] = video_info.common_info.modification_time;
    json_object["fileSize"] = video_info.common_info.file_size;
    json_object["videoDuration"] = video_info.unique_info.duration;
    json_object["burstImgCount"] = 0;
    json_object["astroTargetName"] = "";
    json_object["panoImgCount"] = 0;
    json_object["fileState"] = video_info.common_info.file_state;

    json_object["basicParams"] = hv::Json();
    
    json_object["featureParams"] = hv::Json();
    hv::Json duration_json;
    duration_json["name"] = "duration";
    duration_json["value"] = std::to_string(video_info.unique_info.duration);
    json_object["featureParams"].push_back(duration_json);

    hv::Json width_json;
    width_json["name"] = "width";
    width_json["value"] = std::to_string(video_info.unique_info.width);
    json_object["featureParams"].push_back(width_json);

    hv::Json height_json;
    height_json["name"] = "height";
    height_json["value"] = std::to_string(video_info.unique_info.height);
    json_object["featureParams"].push_back(height_json);

    return json_object;
}

hv::Json HttpServer::getAlbumBurstJson(BurstInfo& burst_info) {
    hv::Json json_object;
    json_object["mediaType"] = MEDIA_BURST;
    json_object["filePath"] = burst_info.common_info.file_path;
    json_object["thumbnailPath"] = burst_info.common_info.thumbnail_path;
    json_object["fileName"] = extractNthFolderName(burst_info.common_info.file_path, 1);
    json_object["modificationTime"] = burst_info.common_info.modification_time;
    json_object["fileSize"] = burst_info.common_info.file_size;
    json_object["videoDuration"] = 0;
    json_object["burstImgCount"] = burst_info.unique_info.file_count;
    json_object["astroTargetName"] = "";
    json_object["panoImgCount"] = 0;

    json_object["basicParams"] = hv::Json();
    
    json_object["featureParams"] = hv::Json();
    hv::Json file_count_json;
    file_count_json["name"] = "fileCount";
    file_count_json["value"] = std::to_string(burst_info.unique_info.file_count);
    json_object["featureParams"].push_back(file_count_json);

    return json_object;

}

hv::Json HttpServer::getAlbumPanoJson(PanoInfo& pano_info) {
    hv::Json json_object;
    json_object["mediaType"] = MEDIA_PANO;
    json_object["filePath"] = pano_info.common_info.file_path;
    json_object["thumbnailPath"] = pano_info.common_info.thumbnail_path;
    json_object["fileName"] = extractNthFolderName(pano_info.common_info.file_path, 1);
    json_object["modificationTime"] = pano_info.common_info.modification_time;
    json_object["fileSize"] = pano_info.common_info.file_size;
    json_object["videoDuration"] = 0;
    json_object["burstImgCount"] = 0;
    json_object["astroTargetName"] = "";
    json_object["panoImgCount"] = pano_info.unique_info.row * pano_info.unique_info.col;

    json_object["basicParams"] = hv::Json();
    
    json_object["featureParams"] = hv::Json();
    hv::Json row_json;
    row_json["name"] = "row";
    row_json["value"] = std::to_string(pano_info.unique_info.row);
    json_object["featureParams"].push_back(row_json);

    hv::Json col_json;
    col_json["name"] = "col";
    col_json["value"] = std::to_string(pano_info.unique_info.col);
    json_object["featureParams"].push_back(col_json);

    return json_object;
}

hv::Json HttpServer::getAlbumAstroJson(AstroInfo& astro_info) {
    hv::Json json_object;
    json_object["mediaType"] = MEDIA_ASTRO;
    json_object["filePath"] = astro_info.common_info.file_path;
    json_object["thumbnailPath"] = astro_info.common_info.thumbnail_path;
    json_object["fileName"] = extractNthFolderName(astro_info.common_info.file_path, 1);
    json_object["modificationTime"] = astro_info.common_info.modification_time;
    json_object["fileSize"] = astro_info.common_info.file_size;
    json_object["videoDuration"] = 0;
    json_object["burstImgCount"] = 0;
    json_object["astroTargetName"] = astro_info.unique_info.target;

    json_object["basicParams"] = hv::Json();
    hv::Json exp_time_json;
    exp_time_json["name"] = "expTime";
    exp_time_json["value"] = astro_info.unique_info.exp_time;
    json_object["basicParams"].push_back(exp_time_json);

    hv::Json gain_json;
    gain_json["name"] = "gain";
    gain_json["value"] = std::to_string(astro_info.unique_info.gain);
    json_object["basicParams"].push_back(gain_json);
    
    json_object["featureParams"] = hv::Json();
    hv::Json dec_json;
    dec_json["name"] = "dec";
    dec_json["value"] = astro_info.unique_info.dec;
    json_object["featureParams"].push_back(dec_json);

    hv::Json ra_json;
    ra_json["name"] = "ra";
    ra_json["value"] = astro_info.unique_info.ra;
    json_object["featureParams"].push_back(ra_json);

    hv::Json target_json;
    target_json["name"] = "target";
    target_json["value"] = astro_info.unique_info.target;
    json_object["featureParams"].push_back(target_json);

    hv::Json binning_json;
    binning_json["name"] = "binning";
    binning_json["value"] = astro_info.unique_info.binning;
    json_object["featureParams"].push_back(binning_json);

    hv::Json format_json;
    format_json["name"] = "format";
    format_json["value"] = astro_info.unique_info.format;
    json_object["featureParams"].push_back(format_json);

    hv::Json shotsToTake_json;
    shotsToTake_json["name"] = "shotsToTake";
    shotsToTake_json["value"] = std::to_string(astro_info.unique_info.shotsToTake);
    json_object["featureParams"].push_back(shotsToTake_json);

    hv::Json shotsTaken_json;
    shotsTaken_json["name"] = "shotsTaken";
    shotsTaken_json["value"] = std::to_string(astro_info.unique_info.shotsTaken);
    json_object["featureParams"].push_back(shotsTaken_json);

    hv::Json shotsStacked_json;
    shotsStacked_json["name"] = "shotsStacked";
    shotsStacked_json["value"] = std::to_string(astro_info.unique_info.shotsStacked);
    json_object["featureParams"].push_back(shotsStacked_json);

    return json_object;
}

hv::Json HttpServer::getAlbumAllJson(AlbumAllInfo& all_info) {

    hv::Json json_object;
    int media_type = all_info.common_info.media_type;
    json_object["mediaType"] = media_type;
    json_object["filePath"] = all_info.common_info.file_path;
    json_object["thumbnailPath"] = all_info.common_info.thumbnail_path;
    json_object["fileName"] = getFileName(all_info.common_info.file_path);
    json_object["modificationTime"] = all_info.common_info.modification_time;
    json_object["fileSize"] = all_info.common_info.file_size;
    json_object["videoDuration"] = all_info.video_unique_info.duration;
    json_object["burstImgCount"] = all_info.burst_unique_info.file_count;
    json_object["astroTargetName"] = all_info.astro_unique_info.target;
    json_object["panoImgCount"] = all_info.pano_unique_info.row * all_info.pano_unique_info.col;

    json_object["basicParams"] = hv::Json();
    json_object["featureParams"] = hv::Json();

    if (media_type == MEDIA_ASTRO) {
        hv::Json exp_time_json;
        exp_time_json["name"] = "expTime";
        exp_time_json["value"] = all_info.astro_unique_info.exp_time;
        json_object["basicParams"].push_back(exp_time_json);

        hv::Json gain_json;
        gain_json["name"] = "gain";
        gain_json["value"] = std::to_string(all_info.astro_unique_info.gain);
        json_object["basicParams"].push_back(gain_json);

        hv::Json ircut_json;
        gain_json["name"] = "ircut";
        gain_json["value"] = std::to_string(all_info.astro_unique_info.gain);
        json_object["basicParams"].push_back(gain_json);

        hv::Json dec_json;
        dec_json["name"] = "dec";
        dec_json["value"] = all_info.astro_unique_info.dec;
        json_object["featureParams"].push_back(dec_json);

        hv::Json ra_json;
        ra_json["name"] = "ra";
        ra_json["value"] = all_info.astro_unique_info.ra;
        json_object["featureParams"].push_back(ra_json);

        hv::Json target_json;
        target_json["name"] = "target";
        target_json["value"] = all_info.astro_unique_info.target;
        json_object["featureParams"].push_back(target_json);

        hv::Json binning_json;
        binning_json["name"] = "binning";
        binning_json["value"] = all_info.astro_unique_info.binning;
        json_object["featureParams"].push_back(binning_json);

        hv::Json format_json;
        format_json["name"] = "format";
        format_json["value"] = all_info.astro_unique_info.format;
        json_object["featureParams"].push_back(format_json);

        hv::Json shotsToTake_json;
        shotsToTake_json["name"] = "shotsToTake";
        shotsToTake_json["value"] = std::to_string(all_info.astro_unique_info.shotsToTake);
        json_object["featureParams"].push_back(shotsToTake_json);

        hv::Json shotsTaken_json;
        shotsTaken_json["name"] = "shotsTaken";
        shotsTaken_json["value"] = std::to_string(all_info.astro_unique_info.shotsTaken);
        json_object["featureParams"].push_back(shotsTaken_json);

        hv::Json shotsStacked_json;
        shotsStacked_json["name"] = "shotsStacked";
        shotsStacked_json["value"] = std::to_string(all_info.astro_unique_info.shotsStacked);
        json_object["featureParams"].push_back(shotsStacked_json);
    } else if (media_type == MEDIA_BURST) {
        hv::Json file_count_json;
        file_count_json["name"] = "fileCount";
        file_count_json["value"] = std::to_string(all_info.burst_unique_info.file_count);
        json_object["featureParams"].push_back(file_count_json);
    } else if (media_type == MEDIA_VIDEO) {
        hv::Json duration_json;
        duration_json["name"] = "duration";
        duration_json["value"] = std::to_string(all_info.video_unique_info.duration);
        json_object["featureParams"].push_back(duration_json);

        hv::Json width_json;
        width_json["name"] = "width";
        width_json["value"] = std::to_string(all_info.video_unique_info.width);
        json_object["featureParams"].push_back(width_json);

        hv::Json height_json;
        height_json["name"] = "height";
        height_json["value"] = std::to_string(all_info.video_unique_info.height);
        json_object["featureParams"].push_back(height_json);
    } else if (media_type == MEDIA_PANO) {
        hv::Json row_json;
        row_json["name"] = "row";
        row_json["value"] = std::to_string(all_info.pano_unique_info.row);
        json_object["featureParams"].push_back(row_json);

        hv::Json col_json;
        col_json["name"] = "col";
        col_json["value"] = std::to_string(all_info.pano_unique_info.col);
        json_object["featureParams"].push_back(col_json);
    }
    
    return json_object;

}

void HttpServer::setAlbumListRouter() {
    router.POST("/album/list/mediaInfos", [this](HttpRequest* req, HttpResponse* resp) {
        if (req->headers["Content-Type"] == "application/json") {
            int page_index;
            int page_size;
            resp->json["data"] = hv::Json();
            hv::Json json = hv::Json::parse(req->body);

            if (json.contains("pageIndex"))
                page_index = json["pageIndex"].get<int>();

            if (json.contains("pageSize"))
                page_size = json["pageSize"].get<int>();
           
            if (json.contains("mediaType")) {
                int media_type = json["mediaType"].get<int>();
                log_i("media_type = %d, page_index = %d, page_size = %d", media_type, page_index, page_size);

                if (media_type == MEDIA_PICTURE) {
                    std::vector<PictureInfo> picture_info_list;

                    if (page_size == 0)
                        picture_info_list = album_.album_picture_.queryPictureInfoByTime();
                    else {
                        picture_info_list = album_.album_picture_.queryPictureInfoByTime(page_index, page_size);
                    }

                    for (auto& info : picture_info_list) {
                        hv::Json json_object = getAlbumPictureJson(info);
                        resp->json["data"].push_back(json_object);
                    }
                } else if (media_type == MEDIA_VIDEO) {
                    std::vector<VideoInfo> video_info_list;
                    if (page_size == 0)
                        video_info_list = album_.album_video_.queryVideoInfoByTime();
                    else {
                        video_info_list = album_.album_video_.queryVideoInfoByTime(page_index, page_size);
                    }

                    for (int i = 0;i < cam_tele_.getRecordLoadingCount();i++) {
                        VideoInfo video_info;
                        video_info.common_info.modification_time = getSecondsTimestamp();
                        video_info.common_info.file_state = 1;
                        video_info.common_info.file_size = 0;
                        hv::Json json_object = getAlbumVideoJson(video_info);
                        resp->json["data"].push_back(json_object);
                    }

                    for (auto& info : video_info_list) {
                        hv::Json json_object = getAlbumVideoJson(info);
                        resp->json["data"].push_back(json_object);
                    }
                } else if (media_type == MEDIA_BURST) {
                    std::vector<BurstInfo> burst_info_list;
                    if (page_size == 0)
                        burst_info_list = album_.album_burst_.queryBurstInfoByTime();
                    else {
                        burst_info_list = album_.album_burst_.queryBurstInfoByTime(page_index, page_size);
                    }

                    for (auto& info : burst_info_list) {
                        hv::Json json_object = getAlbumBurstJson(info);
                        resp->json["data"].push_back(json_object);
                    }
                } else if (media_type == MEDIA_PANO) {
                    std::vector<PanoInfo> pano_info_list;
                    if (page_size == 0)
                        pano_info_list = album_.album_pano_.queryPanoInfoByTime();
                    else {
                        pano_info_list = album_.album_pano_.queryPanoInfoByTime(page_index, page_size);
                    }

                    for (auto& info : pano_info_list) {
                        hv::Json json_object = getAlbumPanoJson(info);
                        resp->json["data"].push_back(json_object);
                    }
                } else if (media_type == MEDIA_ASTRO) {
                    std::vector<AstroInfo> astro_info_list;
                    if (page_size == 0)
                        astro_info_list = album_.album_astro_.queryAstroInfoByTime();
                    else {
                        astro_info_list = album_.album_astro_.queryAstroInfoByTime(page_index, page_size);
                    }

                    for (auto& info : astro_info_list) {
                        hv::Json json_object = getAlbumAstroJson(info);
                        resp->json["data"].push_back(json_object);
                    }

                } else if (media_type == MEDIA_ALL) {
                    std::vector<AlbumAllInfo> all_info_list;
                    if (page_size == 0) {
                        all_info_list = album_.queryAlbumAllInfoByTime();
                    } else {
                        all_info_list = album_.queryAlbumAllInfoByTime(page_index, page_size);
                    }

                    for (int i = 0;i < cam_tele_.getRecordLoadingCount();i++) {
                        VideoInfo video_info;
                        video_info.common_info.modification_time = getSecondsTimestamp();
                        video_info.common_info.file_state = 1;
                        video_info.common_info.file_size = 0;
                        hv::Json json_object = getAlbumVideoJson(video_info);
                        resp->json["data"].push_back(json_object);
                    }

                    for (auto& info : all_info_list) {
                        hv::Json json_object = getAlbumAllJson(info);
                        resp->json["data"].push_back(json_object);
                    }
                }
            }
            resp->json["code"] = 0;
        }

        return 200;
    });

    // 删除相册图片
    router.POST("/album/delete", [this](HttpRequest* req, HttpResponse* resp) {

        if (req->headers["Content-Type"] == "application/json") {
            resp->json["data"] = hv::Json();
            hv::Json json = hv::Json::parse(req->body);

            for (const auto& data : json["datas"]) {
                int media_type = data["mediaType"];
                std::string file_path = data["filePath"];
                std::string file_name = data["fileName"];
                hv::Json data_json;
                data_json["mediaType"] = media_type;
                data_json["filePath"] = file_path;
                data_json["fileName"] = file_name;

                switch (media_type) {
                    case 1:
                        if (album_.album_picture_.deletePicture(file_path))
                            data_json["isSuccess"] = true;
                        else
                            data_json["isSuccess"] = false;
                        break;
                    case 2:
                        if (album_.album_video_.deleteVideo(file_path))
                            data_json["isSuccess"] = true;
                        else
                            data_json["isSuccess"] = false;
                        break;
                    case 3:
                        if (album_.album_burst_.deleteDirectory(file_path))
                            data_json["isSuccess"] = true;
                        else
                            data_json["isSuccess"] = false;
                        break;
                    case 4:
                        if (album_.album_astro_.deleteDirectory(file_path))
                            data_json["isSuccess"] = true;
                        else
                            data_json["isSuccess"] = false;
                        break;
                    case 5:
                        if (album_.album_pano_.deleteDirectory(file_path))
                            data_json["isSuccess"] = true;
                        else
                            data_json["isSuccess"] = false;
                        break;
                }


                resp->json["data"].push_back(data_json);
            }
                resp->json["code"] = 0;
        }

        return 200;
    });

    // // 重命名
    // router.GET("/album/picture/rename", [this](HttpRequest* req, HttpResponse* resp) {
    //     std::string file_path = req->GetParam("file_path");
    //     std::string new_file_path = req->GetParam("new_name");

    //     if (album_.album_picture_.renamePicture(file_path, new_file_path)) {
    //         resp->json["code"] = 0;
    //     } else {
    //         resp->json["code"] = -1;
    //     }

    //     return 200;
    // });
}

void HttpServer::setCheckFileMd5Router() {
    router.GET("/checkMd5", [this](HttpRequest* req, HttpResponse* resp) {
        std::string file_path = req->GetParam("file_path");
        std::string md5 = req->GetParam("md5");

        int ret = compareFileMd5(file_path.c_str(), md5.c_str());
        log_i("checkMd5 ret = %d", ret);
        
        resp->json["code"] = 0;
        resp->json["result"] = ret;
        
        return 200;
    });
}

void HttpServer::setGetParamsConfigRouter() {
    router.GET("/getDefaultParamsConfig", [this](HttpRequest* req, HttpResponse* resp) {
        std::string params_config_path = "/userdata/cfg/params_config.json";
        std::ifstream params_config_file(params_config_path);
        if (!params_config_file.is_open()) {
            log_e("can not open params_config file");
            resp->json["code"]= -HTTP_PARSE_JSON_ERROR;
            return 200;
        }

        try {
            params_config_file >> (resp->json["data"]);
            resp->json["code"] = 0;
        } catch (const std::exception& e) {
            resp->json["code"] = -HTTP_PARSE_JSON_ERROR;
            log_i("An exception occurred: %s", e.what());
        }
        
        params_config_file.close();

        return 200;
    });
}


// 固件上传接口
void HttpServer::setUploadFirmwareRouter() {
    router.POST("/uploadFirmware", [this](HttpRequest* req, HttpResponse* resp) {
        std::lock_guard<std::mutex> lock(upgrade_firmware_mutex);

        // log_i("Received HTTP Headers:");
        // for (const auto& header : req->headers) {
        //     log_i("%s: %s", header.first.c_str(), header.second.c_str());
        // }

        const std::string content_type = req->headers["Content-Type"];
        log_i("uploadFirmware content-Type = %s", content_type.c_str());
        resp->json["code"] = -HTTP_INVAID_PARAM;

        if (content_type.find("multipart/form-data") != std::string::npos) {
            size_t boundary_start = content_type.find("boundary=");
            if (boundary_start != std::string::npos) {
                std::string boundary = content_type.substr(boundary_start + 9);
                hv::MultiPart mp;
                
                if (hv::parse_multipart(req->body, mp, boundary.c_str()) == 0) {
                    // Process the multipart content
                    std::string md5_str;
                    std::string save_path;

                    for (const auto& part : mp) {
                        const std::string& part_name = part.first;
                        const hv::FormData& part_data = part.second;
                        
                        log_i("part_name = %s", part_name.c_str());

                        if (part_name == "md5") {
                            log_i("md5 = %s, md5 size = %d", part_data.content.c_str(), part_data.content.size());
                            md5_str = part_data.content;
                        }

                        if (!part_data.filename.empty()) {
                            std::string uploaded_filename = part_data.filename;
                            log_i("uploaded filename = %s", uploaded_filename.c_str());
                            // log_i("uploaded file content = %s", part_data.content.c_str());
                            save_path = "/tmp/" + uploaded_filename;

                            std::ofstream file_stream(save_path, std::ios::binary);
                            if (file_stream.is_open()) {
                                file_stream.write(part_data.content.c_str(), part_data.content.length());
                                file_stream.close();
                            } 
                        }                      
                    }

                    if (fs::exists(save_path)) {
                        int ret = compareFileMd5(save_path.c_str(), md5_str.c_str());
                        log_i("checkMd5 ret = %d", ret);
                        resp->json["code"] = ret;
                        if (ret == 0) {
                            resp->json["code"] = upgradeFirmware(save_path);
                            fileSync();
                        }
                            
                    } else {
                            resp->json["code"] = -HTTP_FILE_NOT_EXIST;
                    }            
                }
            } 
        } 

        return 200;
    });
}


// 日志下载接口
void HttpServer::setDownloadLogRouter() {
    router.GET("/logInfo", [this](HttpRequest* req, HttpResponse* resp) {
        std::string source_dir = "/userdata/log";
        char mac_address[20] = {0};

        resp->json["data"] = hv::Json();
        resp->json["code"] = -HTTP_FILE_NOT_EXIST;

        system_.getMacAddress(mac_address);

        std::string mac_str(mac_address);
        size_t found = mac_str.find(':');
        while (found != std::string::npos) {
            mac_str.erase(found, 1);
            found = mac_str.find(':');
        }
        std::strcpy(mac_address, mac_str.c_str());

        std::string timestamp = getTimeStamp();

        std::string dest_zip_file_path = "/userdata/log/DWARF_II_LOG_" + std::string(mac_address) + "_" + timestamp + ".zip";
        std::string dest_zip_file_name = "DWARF_II_LOG_" + std::string(mac_address) + "_" + timestamp + ".zip";
        std::string key = "xiaogz741dwarfii";
        std::string rm_cmd = "rm /userdata/log/*.tar /userdata/log/*.zip";
        std::string zip_cmd = "zip -e -P " + key + " " +  dest_zip_file_path + " -jr " + source_dir;

        if (fs::exists(source_dir)) {
            std::system(rm_cmd.c_str());
            std::system(zip_cmd.c_str());
        }

        if (fs::exists(dest_zip_file_path)) {
            resp->json["code"] = HTTP_OK;
            resp->json["data"]["hasLogFile"] = true;
            resp->json["data"]["fileName"] = dest_zip_file_name;
            resp->json["data"]["timestamp"] = timestamp;
            resp->json["data"]["fileSize"] = getFileSizeInt(dest_zip_file_path);
        } else {
            resp->json["data"]["hasLogFile"] = false;
            resp->json["data"]["fileName"] = "";
            resp->json["data"]["timestamp"] = "";
            resp->json["data"]["fileSize"] = 0;
        }

        return 200;
    });

    router.GET("/downloadLog", [this](HttpRequest* req, HttpResponse* resp) {
        std::string source_dir = "/userdata/log";
        
        std::string file_name_path = getFirstFileWithExtension(source_dir, ".zip");

        if (file_name_path != "") {
            log_i("downloadLog file_name = %s", file_name_path);
            std::string file_name = getFileName(file_name_path);
            resp->SetHeader("Content-Type", "application/octet-stream");
            std::string filename_header = "attachment; filename=" + file_name;
            resp->SetHeader("Content-Disposition", filename_header);
            return resp->File(file_name_path.c_str());
        }

        return 200;
    });
}

std::tuple<int, int, int> HttpServer::readVersionInfo(const std::string& file_path) {
    std::ifstream config_file(file_path);
    int major = -1, minor = -1, patch = -1;

    if (config_file.is_open()) {
        std::string line;
        if (std::getline(config_file, line)) {
            std::istringstream iss(line);
            char dot;
            if (iss >> major >> dot >> minor >> dot >> patch) {
                return std::make_tuple(major, minor, patch);
            }
        }
    }

    return std::make_tuple(-1, -1, -1);
}

// 获取固件版本
void HttpServer::setGetFirmwareVersionRouter() {
    router.POST("/firmwareVersion", [this](HttpRequest* req, HttpResponse* resp) {
        resp->json["code"] = HTTP_OK;
        resp->json["data"] = hv::Json();

        std::tuple<int, int, int> version = readVersionInfo("/etc/software_version");
        int major, minor, patch;
        std::tie(major, minor, patch) = version;
        log_i("major = %d, minor = %d, patch = %d", major, minor, patch);

        resp->json["data"]["majorVersion"] = major;
        resp->json["data"]["minorVersion"] = minor;
        resp->json["data"]["patchVersion"] = patch;

        return 200;
    });
}

// 升级固件
int HttpServer::upgradeFirmware(std::string& firmware_path) {
    std::string update_json_path = "/tmp/update.json";
    if (!b_upgrade)
        b_upgrade = true;

    std::string unzip_command = "unzip " + firmware_path + " -o -d /tmp";
    log_i("unzip command = %s", unzip_command.c_str());
    int unzip_result = std::system(unzip_command.c_str());

    if (unzip_result != 0) {
        log_i("failed to unzip");
        b_upgrade = false;
        return -HTTP_FILE_NOT_EXIST;
    }

    hv::Json root;
    try {
        std::ifstream json_file(update_json_path);
        if (json_file) {
            json_file >> root;
        } else {
            log_e("Failed to open update.json file: %s", update_json_path.c_str());
            b_upgrade = false;
            return -HTTP_PARSE_JSON_ERROR;
        }
    } catch (const std::exception& e) {
        log_e("Failed to parse update.json: %s", e.what());
        b_upgrade = false;
        return -HTTP_PARSE_JSON_ERROR;
    }

    if (root.find("fileInfo") != root.end() && root["fileInfo"].is_array()) {
        const hv::Json& file_info_array = root["fileInfo"];
        for (const auto& fileInfo : file_info_array) {
            if (fileInfo.find("name") != fileInfo.end() && fileInfo.find("path") != fileInfo.end() && fileInfo.find("needExecute") != fileInfo.end()) {
                std::string name = fileInfo["name"];
                std::string path = fileInfo["path"];
                int needExecute = fileInfo["needExecute"];

                std::string source_file = "/tmp/" + name;
                std::string target_file = path + "/" + name;

                std::string mv_command = "mv " + source_file + " " + target_file;
                int mv_result = std::system(mv_command.c_str());
                
                if (mv_result == 0) {
                    log_i("Moved file: %s to %s", source_file.c_str(), target_file.c_str());
                    if (needExecute == 1) {
                        if (chmod(target_file.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0) {
                            log_i("Set execute permission for: %s", target_file.c_str());
                        } else {
                            log_i("Failed to set execute permission for: %s", target_file.c_str());
                        }
                    }
                } else {
                    log_i("failed to move file: %s to %s", source_file.c_str(), target_file.c_str());
                }        
            }
        }
    }

    return HTTP_OK;
}

void HttpServer::getDeviceInfoRouter() {
    router.POST("/deviceInfo", [this](HttpRequest* req, HttpResponse* resp) {
        std::string ble_wifi_config_path = "/userdata/cfg/ble_wifi.conf";
        std::ifstream ble_wifi_config_file(ble_wifi_config_path);
        hv::Json config_json;
        if (!ble_wifi_config_file.is_open()) {
            log_e("can not open params_config file");
            resp->json["code"]= -1;
            return 200;
        }

        try {
            ble_wifi_config_file >> config_json;
            resp->json["code"] = 0;
        } catch (const std::exception& e) {
            resp->json["code"] = -HTTP_PARSE_JSON_ERROR;
            log_i("An exception occurred: %s", e.what());
            ble_wifi_config_file.close();
            return 200;
        }

        if (!config_json.empty()) {
            try {
                resp->json["data"]["deviceId"] = WS_DEVICE_ID;
                resp->json["data"]["deviceName"] = config_json["deviceName"];
                resp->json["data"]["devicePwd"] = config_json["devicePsd"];
                resp->json["data"]["staWifiName"] = config_json["staName"];
                resp->json["data"]["staWifiPwd"] = config_json["staPsd"];
                resp->json["data"]["apIpAddress"] = AP_IP_ADDRESS;
                resp->json["data"]["staIpAddress"] = config_json["staIpAddress"];
                resp->json["data"]["bleServiceId"] = BLE_UUID_SERVICE;
                if (config_json.contains("wifiConnectedMode"))
                    resp->json["data"]["wifiConnectedMode"] = config_json["wifiConnectedMode"];
                else
                    resp->json["data"]["wifiConnectedMode"] = 0;


                SdCardInfo sdcard_info = system_.getSdCardAvailableAndTotal();
                resp->json["data"]["sdCardInfo"]["hasSdcard"] = sdcard_info.has_sdcard;
                resp->json["data"]["sdCardInfo"]["availableSize"] = sdcard_info.available_size;
                resp->json["data"]["sdCardInfo"]["totalSize"] = sdcard_info.total_size;

                char mac_address[20] = {0};
                system_.getMacAddress(mac_address);
                resp->json["data"]["macAddress"] = std::string(mac_address);
            } catch(const std::exception& e) {
                log_i("parse json error");
                ble_wifi_config_file.close();
                return 200;
            }
        }
        
        ble_wifi_config_file.close();
        fileSync();

        return 200;
    });
}

void HttpServer::setDeviceNameAndPsdRouter() {
    router.POST("/setDeviceNameAndPsd", [this](HttpRequest* req, HttpResponse* resp) {
        int mode = -1;
        std::string value;
        std::string old_value;
        resp->json["data"] = hv::Json();

        hv::Json http_json = hv::Json::parse(req->body);
        if (req->headers["Content-Type"] == "application/json") {
            try {
                mode = http_json["mode"];
                value = http_json["newValue"];
                old_value = http_json["oldValue"];
                log_i("mode = %d, value = %s, old_value = %s", mode, value.c_str(), old_value.c_str());
            } catch (const std::exception& e) {
                resp->json["code"] = -HTTP_PARSE_JSON_ERROR;
                log_i("An exception occurred: %s", e.what());
                return 200;
            }
        } else {
            resp->json["code"] = -HTTP_INVAID_PARAM;
            return 200;
        }

        std::string ble_wifi_config_path = "/userdata/cfg/ble_wifi.conf";
        std::ifstream ble_wifi_config_file(ble_wifi_config_path);
        hv::Json config_json;

        if (!ble_wifi_config_file.is_open()) {
            log_e("can not open params_config file");
            resp->json["code"]= -HTTP_FILE_NOT_EXIST;
            return 200;
        }

        try {
            ble_wifi_config_file >> config_json;
            resp->json["code"] = 0;
        } catch (const std::exception& e) {
            resp->json["code"] = -HTTP_SET_DEVICE_NAME_PASSWORD_FAILED;
            log_i("An exception occurred: %s", e.what());
            ble_wifi_config_file.close();
            return 200;
        }

        if (!config_json.empty()) {
            try {
                if (mode == 1) {
                    log_i("set device name = %s", value.c_str());
                    if (value.size() > MAX_DEVICE_NAME_LNE) {
                        std::string truncated_value = value.substr(0, 23);
                        config_json["deviceName"] = "DWARF_" + truncated_value;
                    } else {
                        config_json["deviceName"] =  "DWARF_" + value;
                    }           
                } else {
                    log_i("set device psd = %s", value.c_str());
                    if (old_value != config_json["devicePsd"]) {
                        resp->json["code"] = -HTTP_SET_DEVICE_NAME_OLD_PASSWORD_ERROR;
                        return 200;
                    } else {
                        config_json["devicePsd"] = value;
                    } 
                }
                resp->json["data"]["mode"] = mode;
                resp->json["data"]["deviceName"] = config_json["deviceName"];
                resp->json["data"]["devicePwd"] = config_json["devicePsd"];
            } catch(const std::exception& e) {
                log_i("parse json error");
                resp->json["code"] = -HTTP_SET_DEVICE_NAME_PASSWORD_FAILED;
                ble_wifi_config_file.close();
                return 200;
            }
        }
        
        ble_wifi_config_file.close();

        // 将修改后的JSON数据保存回原文件
        std::ofstream out_file(ble_wifi_config_path);
        out_file << std::setw(4) << config_json << std::endl;
        out_file.close();

        fileSync();

        return 200;
    });
}

void HttpServer::resetDeviceInfoRouter() {
    router.POST("/resetDeviceInfo", [this](HttpRequest* req, HttpResponse* resp) {
        rgb_power_.waitPressKeyReset();

        resp->json["code"] = 0;
        return 200;
    });
}

void HttpServer::getResetStateRouter() {
    router.POST("/getResetState", [this](HttpRequest* req, HttpResponse* resp) {
        resp->json["code"] = 0;
        resp->json["data"]["isReseted"] = rgb_power_.getPressKeyReset();
        char device_name[20] = {0};
        system_.getDefaultDeviceName(device_name);
        log_i("get default device_name = %s", device_name);
        resp->json["data"]["deviceName"] = std::string(device_name);
        resp->json["data"]["devicePwd"] = "DWARF_12345678";

        return 200;
    });
}

int HttpServer::startServer() {
    server.port = 8082;
    server.service = &router;

    setAlbumRouter();
    setAlbumListRouter();

    setCheckFileMd5Router();
    setGetParamsConfigRouter();
    setUploadFirmwareRouter();
    setDownloadLogRouter();
    setGetFirmwareVersionRouter();
    getDeviceInfoRouter();
    setDeviceNameAndPsdRouter();
    resetDeviceInfoRouter();
    getResetStateRouter();

    http_server_run(&server, 0);

    return 0;
}




